package com.library.exception;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.library.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * 功能描述: 拦截的具体操作，权限的认证拦截
 * @Author: LDH
 * @Date: 2022/6/17 16:37
 */
@Slf4j
@Component
public class AuthHandlerInterceptor implements HandlerInterceptor {
    @Autowired
    TokenUtil tokenUtil;
    @org.springframework.beans.factory.annotation.Value("${token.privateKey}")
    private String privateKey;
    @org.springframework.beans.factory.annotation.Value("${token.yangToken}")
    private Long yangToken;
    @Value("${token.oldToken}")
    private Long oldToken;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 权限认证的拦截操作.
     */
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        log.info("=======进入拦截器========");
        Map<Object,Object> map0 = new HashMap<>();
        try {
            // 如果不是映射到方法直接通过,可以访问资源.
            if (!(object instanceof HandlerMethod)) {
                return true;
            }
            //为空就返回错误
            String token = httpServletRequest.getHeader("token");
            if (null == token || "".equals(token.trim())) {
                map0.put("message","令牌为空");
                map0.put("code",401);
                map0.put("success",false);
                map0.put("timestamp",String.valueOf(System.currentTimeMillis()));
            }
            else {
                log.info("token:" + token);
                Map<String, String> map = tokenUtil.parseToken(token);
                String userId = map.get("userId");
                String userRole = map.get("userRole");
                long timeOfUse = System.currentTimeMillis() - Long.parseLong(map.get("timeStamp"));
                //1.判断 token 是否过期
                //年轻 token
                if (timeOfUse < yangToken) {
                    log.info("token 未过期");
                }
                //老年 token 就刷新 token
                else if (timeOfUse >= yangToken && timeOfUse < oldToken) {
                    httpServletResponse.setHeader("token",tokenUtil.getToken(userId,userRole));
                }
                //过期 token 就返回 token 无效.
                else {
                    new Thread(() -> {
                        //删除redis中对应的key
                        redisTemplate.delete(userId);
                    }).start();

                    throw new TokenAuthExpiredException();
                }
                //2.角色匹配.
                if ("user".equals(userRole)) {
                    log.info("========user账户============");
                    return true;
                }
                if ("admin".equals(userRole)) {
                    log.info("========admin账户============");
                    return true;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            map0.put("message","令牌检验失败");
            map0.put("code",401);
            map0.put("success",false);
            map0.put("timestamp",String.valueOf(System.currentTimeMillis()));
            log.info("Exception:"+e.getMessage());
        }finally {
            log.info("=======退出拦截器========");
        }
        String jsonMap = new ObjectMapper().writeValueAsString(map0);
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        httpServletResponse.getWriter().println(jsonMap);
        return false;
    }
}
